using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;

namespace UDS.Management.Data.Package
{
    internal class DBManifestDescription
    {
        public ResourceCatalog catalog;
        public Assembly assembly;
        public string manifestPath;
        public string manifestResourceName;
    };

    internal class ResourceCatalog
    {
        private SortedList<string, string> resourceFiles;

        // DBManifestDesc keyed by name
        private Dictionary<string, DBManifestDescription> dbManifests;

        private string GetManifestPath(string manifestResourceName)
        {
            int lastDot = manifestResourceName.LastIndexOf('.');
            if (lastDot != -1)
            {
                int secondLastDot = manifestResourceName.LastIndexOf('.', lastDot - 1);
                if (secondLastDot != -1)
                {
                    return manifestResourceName.Substring(0, secondLastDot);
                }
            }
            return null;
        }

        private static string EscapeToResourceName(string resourceName, char[] separator)
        {
            string[] pathComponents = resourceName.Split(separator);
            // replace all but last component 
            for (int i = 0; i < pathComponents.Length - 1; i++)
            {
                pathComponents[i] = pathComponents[i].Replace(".", "._");
                // If the path component starts with a number, 
                // then the Assembly.GetManifestResourceNames() call will
                // pre-pend the directory with an underscore for some reason
                System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"^[\d]");
                if (r.IsMatch(pathComponents[i]))
                {
                    pathComponents[i] = "_" + pathComponents[i];
                }
            }
            string newPath = "";
            foreach (string path in pathComponents)
            {
                if (string.IsNullOrEmpty(newPath))
                {
                    newPath = path;
                }
                else
                {
                    newPath = newPath + '.' + path;
                }
            }
            return newPath;
        }

        public ResourceCatalog(Assembly assembly)
        {
            string[] ResourceFiles = assembly.GetManifestResourceNames();

            // Look for the manifest file
            if (ResourceFiles != null && ResourceFiles.Length > 0)
            {
                resourceFiles = new SortedList<string, string>();
                dbManifests = new Dictionary<string, DBManifestDescription>();

                foreach (string ResourceFile in ResourceFiles)
                {
                    string Extension = Path.GetExtension(ResourceFile);

                    if (Extension == ".manifest")
                    {
                        DBManifestDescription desc = new DBManifestDescription();
                        desc.catalog = this;
                        desc.assembly = assembly;
                        desc.manifestResourceName = ResourceFile;
                        desc.manifestPath = GetManifestPath(ResourceFile);
                        dbManifests.Add(ResourceFile, desc);
                    }
                    else
                    {
                        this.resourceFiles.Add(ResourceFile.ToLower(), ResourceFile);
                    }
                }
            }
        }

        public string GetFileResourceName(DBManifestDescription desc, string name)
        {
            // Need to change from a file name to a resource name
            string resourceName = EscapeToResourceName(name, new char[] { Path.DirectorySeparatorChar });
            resourceName = String.Format("{0}.{1}", desc.manifestPath, resourceName);

            string resName;
            if (resourceFiles.TryGetValue(resourceName.ToLower(), out resName))
            {
                return resName;
            }
            return null;
        }

        public List<string> GetRecursiveResourceName(DBManifestDescription desc, string name, bool recursive)
        {
            List<string> files = new List<string>();
            string resourceName = string.Format("{0}.{1}", desc.manifestPath, name);
            foreach (string info in this.resourceFiles.Keys)
            {
                if (info.StartsWith(resourceName.ToLower()))
                {
                    if (recursive)
                    {
                        files.Add(resourceFiles[info]);
                    }
                    else
                    {
                        string remaining = info.Substring(resourceName.Length + 1);

                        if (remaining.IndexOf('.') == remaining.LastIndexOf('.'))
                            files.Add(resourceFiles[info]);
                    }
                }
            }

            if (files != null && files.Count > 0)
            {
                return files;
            }
            else
            {
                return null;
            }
        }

        public DBManifestDescription GetDBManifestDescritpion(string packageName)
        {
            DBManifestDescription desc;
            if (dbManifests.TryGetValue(packageName, out desc))
            {
                return desc;
            }
            else
            {
                return null;
            }
        }

        public ICollection<string> GetPackages()
        {
            return dbManifests.Keys;
        }
    }
}
